using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace GeneratorLibrary.ClassGeneratorLibrary {
    public class Column {
        string memberName, propertyName, columnName, dataType;

        public string DataType {
            get { return dataType; }
        }
        
        
        string member, property, dacAttribute, extraMethod = "";

        bool isIdentity, isPrimaryKey, isNullable, isForeignKey, isUniqueConstraint;

        public bool IsUniqueConstraint {
            get { return isUniqueConstraint; }
        }

        public bool IsNullable {
            get { return isNullable; }
        }

        SqlDbType sqlDataType;
        string nullValue = "null";

        public string NullValue {
            get { return nullValue; }
        }

        public string ColumnName {
            get { return columnName; }
         }
        public string DacAttribute {
            get { return dacAttribute; }
        }

        public string Property {
            get { return property; }
        }
        public string ExtraMethod {
            get { return extraMethod; }
        }
        public string Member {
            get { return member; }
        }
        public bool IsPrimaryKey {
            get { return isPrimaryKey; }
        }

        public bool IsForeignKey {
            get { return isForeignKey; }
        }

        public Column(DataRow dr) {
            isIdentity = ((int)dr["IsIdentity"] == 1);
            isPrimaryKey = ((int)dr["IsPrimaryKey"] == 1);
            isNullable = ((int)dr["IsNullable"] == 1);
            isForeignKey = ((int)dr["IsForeignKey"] == 1);
            isUniqueConstraint = ((int)dr["IsUniqueConstraint"] == 1);

            columnName = dr["ColumnName"].ToString();

            string temp = dr["DataType"].ToString();
            dataType = parseDataType(ref temp);
            try {
                sqlDataType = (SqlDbType)Enum.Parse(typeof(SqlDbType), temp, true);
            } catch {
                throw new Exception("Currently, this program is not set up to deal with columns of type '" + dataType + "'. Column = " + columnName);
            }

            generate();
        }

        private string parseDataType(ref string sqlDataType) {
            switch (sqlDataType.ToLower()) {
                case "bigint":
                    if (isPrimaryKey || (isForeignKey && !isNullable))
                        nullValue = "0";
                    return "long" + (isNullable ? "?" : "");
                case "binary":
                case "image":
                case "timestamp":
                case "varbinary":
                    return "byte[]";
                case "bit":
                    return "bool" + (isNullable ? "?" : ""); ;
                case "char":
                case "nchar":
                case "ntext":
                case "text":
                case "nvarchar":
                case "varchar":
                case "xml":
                    return "string";
                case "datetime":
                case "smalldatetime":
                case "date":
                case "time":
                case "datetime2":
                case "datetimeoffset":
                    return "DateTime" + (isNullable ? "?" : ""); ;
                case "decimal":
                case "money":
                case "smallmoney":
                    return "decimal" + (isNullable ? "?" : ""); ;
                case "float":
                    return "float" + (isNullable ? "?" : ""); ;
                case "int":
                    if (isPrimaryKey || (isForeignKey && !isNullable))
                        nullValue = "0";
                    return "int" + (isNullable ? "?" : ""); ;
                case "real":
                    return "double" + (isNullable ? "?" : ""); ;
                case "uniqueidentifier":
                    return "Guid";
                case "smallint":
                    if (isPrimaryKey || (isForeignKey && !isNullable))
                        nullValue = "0";
                    return "short" + (isNullable ? "?" : ""); ;
                case "tinyint":
                    if (isPrimaryKey || (isForeignKey && !isNullable))
                        nullValue = "0";
                    return "byte" + (isNullable ? "?" : ""); ;
                case "variant":
                case "sql_variant":
                    sqlDataType = "Variant";
                    return "object";
                case "udt":
                case "structured":
                    return "object";
                case "numeric":
                    sqlDataType = "Decimal";
                    return "decimal" + (isNullable ? "?" : ""); 
            }
            return null;
        }

        private void generate() {
            if (isPrimaryKey && isIdentity) {
                memberName = "id";
                propertyName = "Id";
                extraMethod = "public bool IsNew() {\nreturn id == 0; \n}\n";
            } else {
                memberName = columnName.Substring(0, 1).ToLower() + columnName.Remove(0, 1);
                propertyName = columnName.Substring(0, 1).ToUpper() + columnName.Remove(0, 1);
            }

            if (isNullable && nullValue != "null") {
                member = dataType + " " + memberName + " = " + nullValue + ";\n";
            } else {
                member = dataType + " " + memberName + ";\n";
            }
            property = "public " + dataType + " " + propertyName + " {\n" + "get { return " + memberName + "; }\nset{ " +
                memberName + " = value; }\n}\n";

            if (isPrimaryKey) {
                if (sqlDataType == SqlDbType.Int) {
                    if ((isNullable || isIdentity) && nullValue != "null") {
                        dacAttribute = "[PKSqlColumn(\"" + columnName + "\", " + nullValue + ")]";
                    } else {
                        dacAttribute = "[PKSqlColumn(\"" + columnName + "\")]";
                    }
                } else {
                    dacAttribute = "[PKSqlColumn(\"" + columnName + "\", SqlDbType." + Enum.GetName(typeof(SqlDbType), sqlDataType)
                        + ", " + nullValue + ")]";
                }
            } else if (sqlDataType == SqlDbType.VarChar) {
                if (isNullable && nullValue != "null") {
                    dacAttribute = "[StringSqlColumn(\"" + columnName + "\", " + nullValue + ")]";
                } else {
                    dacAttribute = "[StringSqlColumn(\"" + columnName + "\")]";
                }
            } else {
                if (isNullable && nullValue != "null") {
                    dacAttribute = "[SqlColumn(\"" + columnName + "\", SqlDbType." + Enum.GetName(typeof(SqlDbType), sqlDataType)
                        + ", " + nullValue + ")]";
                } else {
                    dacAttribute = "[SqlColumn(\"" + columnName + "\", SqlDbType." + Enum.GetName(typeof(SqlDbType), sqlDataType) + ")]";
                }
            }
        }
    }
}
